package com.manage.competition.service.impl;

import com.manage.competition.common.ServerResponse;
import com.manage.competition.entity.Role;
import com.manage.competition.entity.User;
import com.manage.competition.mapper.UserMapper;
import com.manage.competition.redis.KeyPrefix;
import com.manage.competition.redis.RedisService;
import com.manage.competition.redis.ValidPrefix;
import com.manage.competition.repository.UserRepository;
import com.manage.competition.service.IEmailValidateService;
import com.manage.competition.service.IFileService;
import com.manage.competition.service.IRoleService;
import com.manage.competition.service.IUserService;
import com.manage.competition.util.CurrentUserUtil;
import com.manage.competition.util.HashPasswordUtil;
import com.manage.competition.util.SnowflakeUtil;
import com.manage.competition.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Create with IDEA
 *
 * @Author:Vantcy
 * @Date: Create in 14:40 2019/1/23
 * @Description:
 */
@Service
@Slf4j
public class UserServiceImpl extends BaseServiceImpl implements IUserService {

    private static final KeyPrefix VALID_KEY_PREFIX = ValidPrefix.getByEmailValid;

    private static final String VAILD_PREFIX = VALID_KEY_PREFIX.getPrefix();

    private final static long EXPIRE_TIME = 60 * 10 ;


    @Autowired
    private IEmailValidateService emailValidateService;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IFileService fileService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRepository userRepository;


    static final private String USERIMAGE = "userImage";

    @Override
    public ServerResponse<UserVo> login(String username, String password) {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        if (subject.isAuthenticated()) {
            User user = (User)subject.getPrincipal();
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(user,userVo);
            userVo.setRoles(roleService.findRole(user.getId()));
            userVo.setToken(subject.getSession().getId().toString());
            return ServerResponse.createBySuccess("登录成功",userVo);
        }
        return ServerResponse.createByErrorMessage("登录失败");
    }

    @Override
    public ServerResponse<String> logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return ServerResponse.createBySuccess("账号已退出");
    }

    @Override
    public boolean registerValid(String mail) {
        String code = (String) redisService.get(VAILD_PREFIX+mail);
        if (code==null){
            String verifyCode = String.valueOf(new Random().nextInt(899999) + 100000);
            code = verifyCode;
            redisService.set(VAILD_PREFIX+mail, code,EXPIRE_TIME);
        }
        try {
            emailValidateService.sendSimpleMail(mail,code);
        }catch (MailException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public List<UserVo> getUserList() {
        List<User> users = userRepository.findAll();
        List<UserVo> userVos = new ArrayList<>();
        for (User user: users){
            List<String> role =  roleService.findRole(user.getId());
            UserVo userVo = new UserVo();
            BeanUtils.copyProperties(user,userVo);
            userVo.setRoles(role);
            userVos.add(userVo);
        }
        return userVos;
    }

    @Override
    public List<UserVo> getTeacherList() {
        List<User> users = userRepository.findAll();
        List<UserVo> userVos = new ArrayList<>();
        for (User user: users){
            List<String> role =  roleService.findRole(user.getId());
            for (String ro: role){
                if(ro.equals("teacher")){
                    UserVo userVo = new UserVo();
                    BeanUtils.copyProperties(user,userVo);
                    userVo.setRoles(role);
                    userVos.add(userVo);
                }
            }


        }
        return userVos;
    }

    @Override
    public Integer setUserInfo(User user) {
        if (user.getId()!=null){
            return userMapper.updateByPrimaryKeySelective(user);
        }
        return null;
    }

    @Override
    public int setNewPassword(Long id, String newPassword) {
        User user = userRepository.findById(id).orElse(null);
        if (user!=null){
            user.setPassword(HashPasswordUtil.hashpassword(user.getUsername(),newPassword));
            return userMapper.updateByPrimaryKeySelective(user);
        }
        return 0;
    }

    @Override
    public int setNewRole(Long id, String newRole) {
        User user = userRepository.findById(id).orElse(null);
        Role role = roleService.findUserRole(id);
        if (user!=null&&role!=null){
            role.setRole(newRole);
            return roleService.update(role);
        }
        return 0;
    }

    @Override
    public int setUserStatus(Long id, int status) {
        User user = userRepository.findById(id).orElse(null);
        if (user!=null){
            user.setStatus(status);
            return userMapper.updateByPrimaryKeySelective(user);
        }
        return 0;
    }

    @Override
    public ServerResponse<UserVo> getUserInfo() {
        User user = userRepository.findById(CurrentUserUtil.getCurrentUser().getId()).orElse(null);
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user,userVo);
        return ServerResponse.createBySuccess(userVo);
    }

    @Override
    public User getUserInfo(long userId) {
        return userRepository.findById(userId).orElse(null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int register(String username,String password,String mail,String captcha) {
        String code = (String) redisService.get(VAILD_PREFIX+mail);
        if (code==null){
            return -1;
        }else if (!code.equals(captcha)){
            return 0;
        }else if(userRepository.findByUsername(username)!=null){
            return -2;
        }
        long userId = SnowflakeUtil.nextId();
        User user = new User();
        user.setUsername(username);
        user.setId(userId);
        user.setPassword(HashPasswordUtil.hashpassword(username,password));
        user.setMail(mail);
        user.setCreateUser(username);
        user.setUpdateUser(username);
        Role role = new Role();
        role.setUserId(userId);
        role.setRole("user");
        roleService.insert(role);
        return userMapper.insert(user);
    }

    @Override
    public String upload(MultipartFile prefile) {
        String targetFileName = fileService.upload(prefile,USERIMAGE);
        if (!targetFileName.isEmpty()){
            long userId = CurrentUserUtil.getCurrentUser().getId();
            User user = userRepository.findById(userId).orElse(null);
            if (user.getPrefilePicture()!=null){
                fileService.delete(user.getPrefilePicture(),USERIMAGE);
            }
            User newUser = new User();
            newUser.setId(userId);
            newUser.setPrefilePicture(targetFileName);
            userMapper.updateByPrimaryKeySelective(newUser);
            return targetFileName;
        }
        return null;

    }


}
